#ifdef _WIN32
#include <windows.h>
#endif

#include "GLee.h"
#include <GL/glu.h>

#include "Background.h"
#include "glslshader.h"
#include "TextureManager.h"
#include "GLTexture.h"

Background::Background(void) 
: Entity(), m_shaderProgram(NULL)
{
}

Background::Background(const std::string& textureName)
: Entity(), m_shaderProgram(NULL), m_textureName(textureName)
{
}

Background::~Background(void)
{
}

bool Background::onInitialize()
{
    TextureManager* manager = TextureManager::getInstance();
    if (manager->hasTexture(m_textureName))
    {
        m_texture = manager->getTexture(m_textureName);
    }
    else
    {
        m_texture = boost::shared_ptr<GLTexture>(new GLTexture(m_textureName, GL_LINEAR, 
                                  GL_LINEAR_MIPMAP_LINEAR, GL_RGB8, GL_RGB,
                                  GL_UNSIGNED_BYTE, true));
        manager->addTexture(m_texture);
    }

    GLfloat vertex [] = { 0.0f, 0.0f, //First Square vertex
        static_cast<GLfloat>(m_texture->width()), 0.0f,
        static_cast<GLfloat>(m_texture->width()), static_cast<GLfloat>(m_texture->height()),
        0.0f, static_cast<GLfloat>(m_texture->height())  //Last Square vertex
    };

    glGenBuffers(1, &m_vertexBuffer); //Generate a buffer for the vertices
    glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); //Bind the vertex buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, &vertex[0], GL_STATIC_DRAW); //Send the data to OpenGL

    GLfloat texCoords [] = { 0.0f, 0.0f, 
                             1.0f, 0.0f,
                             1.0f, 1.0f,
                             0.0f, 1.0f 
    };

    glGenBuffers(1, &m_texCoordBuffer); //Generate a buffer for the vertices
    glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer); //Bind the vertex buffer
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 8, &texCoords[0], GL_STATIC_DRAW); //Send the data to OpenGL

    m_shaderProgram = new GLSLProgram("data/shaders/simple-texture.vert", 
                                        "data/shaders/simple-texture.frag");

    if (!m_shaderProgram->initialize())
    {
        std::cerr << "Could not initialize the Background shaders" << std::endl;
        return false;
    }

    m_shaderProgram->bindAttrib(0, "a_Vertex");
    m_shaderProgram->bindAttrib(1, "a_TexCoord0");
    m_shaderProgram->linkProgram();

    return true;

}

void Background::onPrepare(float dT)
{
}

void Background::onRender() const
{
    static float modelviewMatrix[16];
    static float projectionMatrix[16];

    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

    glPushMatrix();
    glTranslatef(static_cast<GLfloat> (m_position.x), 
                 static_cast<GLfloat> (m_position.y), 
                 m_position.z);

    glGetFloatv(GL_MODELVIEW_MATRIX, modelviewMatrix);
    glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix);

    m_shaderProgram->bindShader();
    m_shaderProgram->sendUniform4x4("modelview_matrix", modelviewMatrix);
    m_shaderProgram->sendUniform4x4("projection_matrix", projectionMatrix);
    m_shaderProgram->sendUniform("texture0", 0);

    glBindTexture(GL_TEXTURE_2D, m_texture->textureID());

    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
    glVertexAttribPointer((GLint)0, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer);
    glVertexAttribPointer((GLint)1, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glDrawArrays(GL_QUADS, 0, 4);

    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);

    glPopMatrix();

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);

}

void Background::onPostRender()
{
}

void Background::onShutdown()
{
}

void Background::onDestroy()
{
}
